package com.thouiot.modbus.config.properties;

import com.serotonin.modbus4j.serial.SerialPortWrapper;
import com.thouiot.common.exception.TiotRuntimeException;
import com.thouiot.modbus.contant.ModbusConstants;
import com.thouiot.modbus.exception.ModbusErrorCodeEnum;
import purejavacomm.CommPort;
import purejavacomm.CommPortIdentifier;
import purejavacomm.SerialPort;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

/**
 * @description 实现串口通信基础设置
 * @author wangkai
 * @date 2025/04/10 17:53
 */
public class SerialPortWrapperImpl implements SerialPortWrapper {
    /**
     * 串口对象
     */
    private SerialPort serialPort;

    /**
     * 串口
     */
    private String port;

    /**
     * 波特率，默认 9600
     */
    private Integer baudRate = 9600;

    /**
     * 数据位的位数，RTU是8位，ASCII是7位
     * 默认 8
     */
    private Integer dataBits = SerialPort.DATABITS_8;

    /**
     * 停止位的位数，如果无奇偶校验为2，有奇偶校验为1
     * 默认 1
     */
    private Integer stopBits = SerialPort.STOPBITS_1;

    /**
     * 奇偶校验位，无校验是0，奇校验是1，偶校验是2
     * 默认 0
     */
    private Integer parity = SerialPort.PARITY_NONE;

    /**
     * 硬件之间输入流应答控制
     */
    private Integer flowControlIn = 0;

    /**
     * 硬件之间输出流应答控制
     */
    private Integer flowControlOut = 0;

    public SerialPortWrapperImpl() {
        super();
    }

    public SerialPortWrapperImpl(String port, int baudRate, int dataBits, int stopBits, int parity,
                                 int flowControlIn, int flowControlOut) {
        this.port = port;
        this.baudRate = baudRate;
        this.dataBits = dataBits;
        this.stopBits = stopBits;
        this.parity = parity;
        this.flowControlIn = flowControlIn;
        this.flowControlOut = flowControlOut;
    }

    @Override
    public void close() throws Exception {
        if (serialPort != null) {
            serialPort.close();
        }
    }

    @Override
    public void open() throws Exception {
        try {
            // 通过端口名识别端口
            CommPortIdentifier identifier = CommPortIdentifier.getPortIdentifier(port);
            // 打开端口，并给端口名字和一个timeout（打开操作的超时时间）
            CommPort commPort = identifier.open(port, ModbusConstants.SERIAL_OPEN_TIMEOUT);
            // 判断是不是串口
            if (commPort instanceof SerialPort) {
                serialPort = (SerialPort) commPort;
                // 设置一下串口的波特率等参数
                serialPort.setSerialPortParams(baudRate, dataBits, stopBits, parity);
            }
        } catch (Exception e) {
            throw new TiotRuntimeException(ModbusErrorCodeEnum.SERIAL_PORT_OPEN_ERROR);
        }
    }

    @Override
    public InputStream getInputStream() {
        InputStream in = null;
        try {
            in = serialPort.getInputStream();
        } catch (IOException e) {
            throw new TiotRuntimeException(ModbusErrorCodeEnum.SERIAL_OPEN_INPUT_ERROR);
        }

        return in;
    }

    @Override
    public OutputStream getOutputStream() {
        OutputStream out = null;
        try {
            out = serialPort.getOutputStream();
        } catch (IOException e) {
            throw new TiotRuntimeException(ModbusErrorCodeEnum.SERIAL_OPEN_OUTPUT_ERROR);
        }

        return out;
    }

    @Override
    public int getBaudRate() {
        return this.baudRate;
    }

    @Override
    public int getDataBits() {
        return this.dataBits;
    }

    @Override
    public int getStopBits() {
        return this.stopBits;
    }

    @Override
    public int getParity() {
        return this.parity;
    }

    @Override
    public int getFlowControlIn() {
        return this.flowControlIn;
    }

    @Override
    public int getFlowControlOut() {
        return this.flowControlOut;
    }

    public SerialPort getSerialPort() {
        return serialPort;
    }

    public void setSerialPort(SerialPort serialPort) {
        this.serialPort = serialPort;
    }

    public String getPort() {
        return port;
    }

    public void setPort(String port) {
        this.port = port;
    }

    public void setBaudRate(Integer baudRate) {
        this.baudRate = baudRate;
    }

    public void setDataBits(Integer dataBits) {
        this.dataBits = dataBits;
    }

    public void setStopBits(Integer stopBits) {
        this.stopBits = stopBits;
    }

    public void setParity(Integer parity) {
        this.parity = parity;
    }

    public void setFlowControlIn(Integer flowControlIn) {
        this.flowControlIn = flowControlIn;
    }

    public void setFlowControlOut(Integer flowControlOut) {
        this.flowControlOut = flowControlOut;
    }
}
